package org.xx.armory.spring5.jdbc;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.List.copyOf;
import static org.apache.commons.lang3.StringUtils.join;
import static org.xx.armory.commons.Validators.rejectIf;
import static org.xx.armory.commons.Validators.rejectIfNull;

/**
 * 表示实体的复合主键。
 */
public final class CompositeKey {
    private final List<Object> data;

    /**
     * 初始化复合主键。
     *
     * @param data
     *         主键的值。
     */
    public CompositeKey(
            Collection<Object> data
    ) {
        this.data = copyOf(data);
    }

    /**
     * 使用给定的主键值创建一个复合主键。
     *
     * @param firstData
     *         第一个主键的值。
     * @param secondData
     *         第二个主键的值。
     * @param otherData
     *         其它主键的值。
     * @return 复合主键。
     * @throws IllegalArgumentException
     *         如果某一个主键值是{@code null}。
     */
    public static CompositeKey of(
            Object firstData,
            Object secondData,
            Object... otherData
    ) {
        rejectIfNull(firstData, "firstData");
        rejectIfNull(secondData, "secondData");

        if (otherData != null) {
            rejectIf(() -> stream(otherData).anyMatch(Objects::isNull), "Any element muse not be null", "others");

            final var data = new ArrayList<>(otherData.length + 2);
            data.add(firstData);
            data.add(secondData);
            data.addAll(asList(otherData));

            return new CompositeKey(data);
        } else {
            return new CompositeKey(asList(firstData, secondData));
        }
    }

    public final Object get(
            int i
    ) {
        return this.data.get(i);
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.data);
    }

    @Override
    public boolean equals(
            Object obj
    ) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof CompositeKey)) {
            return false;
        }
        final var other = (CompositeKey) obj;
        return Objects.equals(this.data, other.data);
    }

    @Override
    public final String toString() {
        return "<" + join(this.data, ",") + ">";
    }
}
